%% Author: wintereagle
%% Created: 2007-1-6
%% Description: TODO: Add desciption to aleph_dht_action_findnodes
-module(aleph_dht_action_findnodes).
-include("aleph_data_interface.hrl").
-include("aleph_action_macros.hrl").

-import(aleph_dht_session,[new_session/1,find_session/1,delete_session/1,insert_session/1,
         clear_sessions/0,set_answered/3,set_found/3,set_queried/3,is_queried_has_id/2,
         is_answered_has_id/2,set_finished/1,set_outstanding/2,get_outstanding/1]).
-import(aleph_dht_actions,[sort/1]). 
-import(aleph_utility,[while/2]).

-export([find_nodes/2]).

find_nodes(Id,Nodes)->
    Session=aleph_dht_session:new_session(Id),
    RootId=aleph_dht_table:root_id(),
    Found=lists:foldl(fun(X,ACC)->
        case X(id)== RootId of
            false->dict:store(X(id),X,ACC);
            true->ACC
        end end,dict:new(),Nodes),
    aleph_dht_table:insert_session(Session({found,Found})),
    schedule(Session(key)).
      
schedule(Key)->
   Session=find_session(Key),
   case Session(finished) of
     true->none;
     false->
      [H|T]=sort(dict:to_list(Session(found))),
      Target=Session(target),
      Root_id=alpeh_dht_table:root_id(),
      schedule_helper(H,T,{Key,Session,Root_id,Target}),
      case get_outstanding(Key)==0 of
          false->none;
          true->set_finished(Key),
                session_done(Key,[H|T])
      end
   end.

schedule_helper(_,[],_)->none;
schedule_helper({Id,Node},[H|T],{Key,Session,Root_id,Target}=Context)->                          
       case Node(id)=:=Target of
            true ->set_finished(Key),
                   session_done(Key,[Node]),
                   none;                  
            false->
                case (is_queried_has_id(Session,Id)==false andalso Node(id)=/=Root_id) of
                     true->      
                         Sess=find_session(Key),                       
                         set_outstanding(Sess,Sess(outstanding)+1),
                         set_queried(Sess,Node(id),true),
                         send_find_nodes(Node,Target,Root_id,Key);                              
                     false-> none                            
                end,      
                case get_outstanding(Key)>=?CONCURRENT_REQS of
                     false ->none;
                     true->schedule_helper(H,T,Context)
                end     
        end.
session_done(Key,Data)->
    ok.
send_find_nodes(Node,Target,Root_id,Key)->  
    aleph_dht_rpc:send(Node(host),Node(port),?REQ_FINDNODE(Target,Root_id,Key)).